package org.example.utils;

import org.example.service.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @description: <br>
 * @date: 2022/3/19 10:22 <br>
 * @author: ichpeng@hotmail.com <br>
 * @version: 1.0 <br>
 */
public class LogUtil {

    /**
     * 日志级别枚举
     */
    public static enum LEVEL{
        ERROR(4, "ERROR"),
        WARN(3, "WARN"),
        INFO(2, "INFO"),
        DEBUG(1, "DEBUG"),
        TRACE(0, "TRACE");

        int level;
        String desc;

        LEVEL(int level, String desc) {
            this.level = level;
            this.desc = desc;
        }

        public int getLevel() {
            return level;
        }

        public String getDesc() {
            return desc;
        }
    }

    private static void log(Logger logger, LEVEL level, String msg, Throwable throwable){
        msg = loggerPre(logger, level) + msg;
        String stackTrace = exceptionHandle(throwable);
        stackTrace = stackTrace.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("\n", "<br/>").replaceAll("\t","&nbsp;&nbsp;&nbsp;&nbsp;");
        switch(level){
            case ERROR:
                sendToClient(LEVEL.ERROR.getDesc(), msg, stackTrace);
            case WARN:
                sendToClient(LEVEL.WARN.getDesc(), msg, stackTrace);
            case INFO:
                sendToClient(LEVEL.INFO.getDesc(), msg, stackTrace);
            case DEBUG:
                sendToClient(LEVEL.DEBUG.getDesc(), msg, stackTrace);
            case TRACE:
                sendToClient(LEVEL.TRACE.getDesc(), msg, stackTrace);
                break;
            default:
                break;
        }

    }

    public static void error(Logger logger, String msg){
        error(logger, msg, null);
    }
    public static void warn(Logger logger, String msg){
        warn(logger,msg, null);
    }
    public static void info(Logger logger, String msg){
        info(logger, msg, null);
    }
    public static void debug(Logger logger, String msg){
        debug(logger, msg, null);
    }
    public static void trace(Logger logger, String msg){
        trace(logger,  msg, null);
    }

    public static void error(Logger logger, String msg, Throwable throwable){
        logger.error(msg, throwable);
        log(logger, LEVEL.ERROR, msg, throwable);
    }
    public static void warn(Logger logger, String msg, Throwable throwable){
        logger.warn(msg, throwable);
        log(logger, LEVEL.WARN, msg, throwable);
    }
    public static void info(Logger logger, String msg, Throwable throwable){
        logger.info(msg, throwable);
        log(logger, LEVEL.INFO, msg, throwable);
    }
    public static void debug(Logger logger, String msg, Throwable throwable){
        logger.debug(msg, throwable);
        log(logger, LEVEL.DEBUG, msg, throwable);
    }
    public static void trace(Logger logger, String msg, Throwable throwable){
        logger.trace(msg, throwable);
        log(logger, LEVEL.TRACE, msg, throwable);
    }

    private static void sendToClient(String keyPre, String msg, String stackTrace) {
        WebSocketServer.webSocketMap.forEach((id, client) -> {
            try {
                if(id.startsWith(keyPre)){
                    WebSocketServer.sendToWeb(msg, id);
                    WebSocketServer.sendToWeb(stackTrace, id);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }


    private static String exceptionHandle(Throwable throwable){
        if(null == throwable){
            return "";
        }
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try{
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }


    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
    private static String loggerPre(Logger logger, LEVEL level){
        String threadName = Thread.currentThread().getName();
        String loggerName = logger.getName();

        return String.format("%s [%s] %s - %s: ", SIMPLE_DATE_FORMAT.format(new Date()), threadName, level.getDesc(), loggerName);
    }

    /**
     * 处理异常的堆栈信息
     * @param args
     */
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogUtil.class);
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try{
            System.out.println(SIMPLE_DATE_FORMAT.format(new Date()));
            System.out.println(Thread.currentThread().getName());
            logger.info("hello world.");
            System.out.println(logger.getName());
            System.out.println(1/0);
        }catch (Exception e){
            try{
                e.printStackTrace(pw);
                System.out.println(sw.toString());
            } finally {
                pw.close();
            }
        }
    }

}
